﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using NJamb.Parser.SubjectBuilders;
using NJamb.Parser.Subjects.Singular;
using NJamb.Specifications.Simple;
using Stile.Patterns.SelfDescribingPredicates;
using Stile.Types.Expressions;
#endregion

namespace NJamb.Specifications.Delta
{
	public interface IRaisePropertyChangedDeltaSpecification<THost> : IDeltaSpecification
		where THost : class, INotifyPropertyChanged {}

	public class RaisePropertyChangedDeltaSpecification<THost> : DeltaSpecification<THost, IEvaluation<string>>,
		IRaisePropertyChangedDeltaSpecification<THost>
		where THost : class, INotifyPropertyChanged
	{
		private readonly Lazy<RaisePropertyChangedAfterSpecification<THost>> _after;
		private string _preconditionResult;

		public RaisePropertyChangedDeltaSpecification(IEvaluable<IEvaluation<string>> before,
			Lazy<string> lazyDescription,
			string expectedPropertyName,
			Func<string> actualPropertyNameGetter)
			: base(before)
		{
			_after =
				new Lazy<RaisePropertyChangedAfterSpecification<THost>>(
					() => new RaisePropertyChangedAfterSpecification<THost>(lazyDescription, expectedPropertyName, actualPropertyNameGetter));
		}

		public override IEvaluable<IEvaluation<string>> After
		{
			get { return _after.Value; }
		}

		public static RaisePropertyChangedDeltaSpecification<THost> Make<TSubject>(ISubjectBuilder<THost> subjectBuilder,
			Expression<Func<THost, TSubject>> propertyExpression)
		{
			Lazy<string> lazyDescription = subjectBuilder.Xray.LazyHostDescription;
			var singularSubject = new SingularSubject<THost>(subjectBuilder.Xray.Expression.Compile(), lazyDescription);
			var before = new RaisePropertyChangedBeforeSpecification<THost>(singularSubject);
			string expectedPropertyName = ExpressionExtensions.GetBodySubstring(propertyExpression);
			return new RaisePropertyChangedDeltaSpecification<THost>(before,
				lazyDescription,
				expectedPropertyName,
				() => before.Evaluate().Result);
		}

		protected override void InspectFirstEvaluation(IEvaluation<string> evaluation)
		{
			base.InspectFirstEvaluation(evaluation);
			_preconditionResult = evaluation.Result;
		}
	}
}
